#pragma once

#include <iostream>
#include <memory>
#include <vector>
#include <errno.h>
#include <cstring>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <poll.h>
#include <unistd.h>
#include "LogMessage.hpp"
#include "Socket.hpp"

const int defaultsize = 100;

class PollServer
{
public:
    PollServer(uint16_t port, size_t size = defaultsize)
        : _size(size)
    {
        _listenSock = new TcpSocket;
        _listenSock->CreateBindListenSocket(port);

        _fds = new struct pollfd[_size];
        if (_fds == nullptr)
        {
            lg.LogMessage(Error, "malloc error");
            exit(0);
        }

        for (int i = 0; i < _size; i++)
            _fds[i].fd = -1;

        _fds[0].fd = _listenSock->GetSockfd();
        _fds[0].events = 0;
        _fds[0].revents = 0;
        _fds[0].events |= POLLIN;
    }

    ~PollServer()
    {
        _listenSock->CloseSockfd();
        delete _listenSock;
        _listenSock = nullptr;

        delete [] _fds;
        _fds = nullptr;
    }

    void Start()
    {
        while (true)
        {
            PrintDebug();
            int n = poll(_fds, _size, -1);
            if (n == 0)
            {
                lg.LogMessage(Debug, "time out, Please try again");
            }
            else if (n == -1)
            {
                lg.LogMessage(Warning, "poll error, errno: %d, strerror: %s", errno, strerror(errno));
            }
            else 
            {
                lg.LogMessage(Debug, "Events ready, Please read");
                Handler();
            }
        }
    }

    void Handler()
    {
        for (int i = 0; i < _size; i++)
        {
            if (_fds[i].fd == -1)
                continue;

            if (_fds[i].revents & POLLIN)
            {
                //读事件已经就绪了
                if (_fds[i].fd == _listenSock->GetSockfd())
                {
                    //监听套接字读事件就绪，有新连接到来
                    _fds[i].revents = 0;
                    InetAddr addr;
                    Socket* sock = _listenSock->AcceptConnect(addr);

                    int posi = 0;
                    for (int posi = 0; posi < _size; posi++)
                    {
                        if (_fds[posi].fd == -1)
                        {
                            _fds[posi].fd = sock->GetSockfd();
                            _fds[posi].events = 0;
                            _fds[posi].revents = 0;
                            _fds[posi].events |= POLLIN;
                            break;
                        }
                    }

                    if (posi == _size)
                    {
                        //方案一：失败
                        lg.LogMessage(Warning, "Space if full, Sorry");
                        sock->CloseSockfd();
                        delete sock;
                        sock = nullptr;
                        //方案二：扩容
                    }
                }
                else 
                {
                    //普通的读事件
                    char buffer[4096];
                    sockaddr_in addr;
                    memset(&addr, 0, sizeof(addr));
                    socklen_t addrlen = sizeof(addr);
                    ssize_t n = recvfrom(_fds[i].fd, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&addr, &addrlen);
                    if (n > 0)
                    {
                        buffer[n] = '\0';
                        lg.LogMessage(Debug, "send message: %s", buffer);
                    }
                    else if (n == 0)
                    {
                        close(_fds[i].fd);
                        _fds[i].fd = -1;
                        _fds[i].events = 0;
                        _fds[i].revents = 0;

                        lg.LogMessage(Debug, "you close the connect, me too");
                    }
                    else 
                    {
                        lg.LogMessage(Warning, "recvfrom error, errno: %d, strerror: %s", errno, strerror(errno));
                    }
                }
            }
        }
    }

    void PrintDebug()
    {
        std::cout << "link sockfd: ";
        for (int i = 0; i < _size; i++)
        {
            if (_fds[i].fd != -1)
                std::cout << _fds[i].fd << " ";
        }
        std::cout << std::endl;
    }

private:
    TcpSocket* _listenSock;
    struct pollfd* _fds;
    size_t _size = 0;
};